package com.ruoyi.web.controller.resourcepool;

import com.ruoyi.common.annotation.SearchLog;
import com.ruoyi.common.constant.ClassesConstants;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.domain.entity.SysDictType;
import com.ruoyi.system.domain.DO.RetrievalFacetField;
import com.ruoyi.system.domain.DO.RetrievalSearchField;
import com.ruoyi.system.domain.DO.RetrievalSearchResult;
import com.ruoyi.system.domain.vo.R;
import com.ruoyi.system.domain.DO.RetrievalSearchParams;
import com.ruoyi.system.protocol.*;
import com.ruoyi.system.utils.RetrievalUtil;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/system/esRetrieval")
public class EsRetrievalController extends BaseRetrievalController {

    private static final Logger LOGGER = LoggerFactory.getLogger(EsRetrievalController.class);

    @Autowired
    private IDynamicSearchService dynamicSearchService;

    @Autowired
    private IDynamicSolrSearchService dynamicSolrSearchService;

    @Autowired
    private IDynamicCacheService dynamicCache;

    @Autowired
    private RetrievalUtil retrievalUtil;

    @Autowired
    private IDynamicDataService dynamicDataService;


    @RequestMapping("/searchById")
    public R searchById(String id) {
//        Map<String, Object> map = dynamicSearchService.queryDocument(ClassesConstants.ELASTICSEARCH_INDEXES, id);
        MatchPhraseQueryBuilder matchPhraseQueryBuilder = QueryBuilders.matchPhraseQuery("stringITS_title", "专用绞车");
        HashMap<String, Object> search = dynamicSearchService.search(ClassesConstants.ELASTICSEARCH_INDEXES, matchPhraseQueryBuilder, null, null, null, null, 1, 100);
        return R.success().data("map", search);
    }


    @SearchLog
    @PostMapping("/search")
    public R search(@RequestBody RetrievalSearchParams retrievalSearchParams) {
        //说明文档 ： https://www.cnblogs.com/wenbronk/p/6432990.html
        QueryBuilder completeQueryStr = new MatchAllQueryBuilder();
        long l = System.currentTimeMillis();
        getSearchField(retrievalSearchParams);
        getFacetField(retrievalSearchParams);
        QueryBuilder searchWordQueryStr = getSearchWordQueryStr(retrievalSearchParams);
        QueryBuilder dbQueryStr = getDbQueryStr(retrievalSearchParams);
        QueryBuilder facetQueryStr = getFacetQueryStr(retrievalSearchParams);
        completeQueryStr = getCompleteQueryStr("AND", completeQueryStr, searchWordQueryStr, dbQueryStr);
        List<RetrievalSearchField> searchFields = retrievalSearchParams.getSearchFields();
        String[] highLightFields = searchFields.stream()
                .filter(x -> x.getHighlightingField().equals("1"))
                .map(x -> {
                    String participle = x.getParticiple();
                    if (ClassesConstants.IS_SEARCH_PARTICIPLE.equals(participle)) {
                        return x.getRetrievalName();
                    }
                    return x.getRetrievalName() + ".keyword";
                }).collect(Collectors.toList()).toArray(new String[]{});
        System.out.println((System.currentTimeMillis()-l)+"ms");
        RetrievalSearchResult elasticSearchResult = dynamicSearchService.list(ClassesConstants.ELASTICSEARCH_INDEXES, completeQueryStr, facetQueryStr, null, null, highLightFields, retrievalSearchParams.getPageNumber(), retrievalSearchParams.getPageSizes());
        long total = elasticSearchResult.getTotal();
        Object time = elasticSearchResult.getTime();
        List<Map<String, Object>> records = elasticSearchResult.getRecords();
        for (Map<String, Object> record : records) {
            handleFilePrefix(record.get("type")+"", record, "out");
        }
        return R.success().data("list", records).data("count", total).data("searchField", searchFields).data("time", time);
    }

    @PostMapping("/getDetailFields")
    public R getDetailFields(@RequestBody RetrievalSearchParams retrievalSearchParams) {
        getDetailField(retrievalSearchParams);
        return R.success().data("list", retrievalSearchParams.getListDisplayFields());
    }

    /**
     * 查询补全
     *
     * @param retrievalSearchParams
     * @return
     */
    @PostMapping("/searchCompletion")
    public R searchCompletion(@RequestBody RetrievalSearchParams retrievalSearchParams) {
        String searchWord = retrievalSearchParams.getSearchWord();
        List<Map<String, Object>> data = new ArrayList<>();
        if (StringUtils.isNotBlank(searchWord)) {
            BoolQueryBuilder qb = QueryBuilders.boolQuery();
            String titleForward = retrievalUtil.replaceRetrievalFieldForward("title");
            QueryBuilder titlePQBuilder = QueryBuilders.prefixQuery(titleForward+".keyword", searchWord).boost(2.0f);
            QueryBuilder fullPinyinQueryBuilder = QueryBuilders.prefixQuery(titleForward+".full_pinyin", searchWord);
            QueryBuilder firstPinyinQueryBuilder = QueryBuilders.prefixQuery(titleForward+".first_pinyin", searchWord);
            qb.should(titlePQBuilder);
            qb.should(fullPinyinQueryBuilder);
            qb.should(firstPinyinQueryBuilder);
            HashMap<String, Object> search = dynamicSearchService.search(ClassesConstants.ELASTICSEARCH_INDEXES, qb, null, new String[]{titleForward}, null, null, retrievalSearchParams.getPageNumber(), retrievalSearchParams.getPageSizes());
            data = (List<Map<String, Object>>) search.get("data");
        }
        return R.success().data("list", data);
    }

    @PostMapping("/facet")
    public R facet(@RequestBody RetrievalSearchParams retrievalSearchParams) {
        String db = retrievalSearchParams.getDb();
        QueryBuilder completeQueryStr = new MatchAllQueryBuilder();
        getSearchField(retrievalSearchParams);
        getFacetField(retrievalSearchParams);
        QueryBuilder searchWordQueryStr = getSearchWordQueryStr(retrievalSearchParams);
        QueryBuilder dbQueryStr = getDbQueryStr(retrievalSearchParams);
        QueryBuilder facetQueryStr = getFacetQueryStr(retrievalSearchParams);
        completeQueryStr = getCompleteQueryStr("AND", completeQueryStr, searchWordQueryStr, dbQueryStr);
        List<RetrievalFacetField> facetFieldList = retrievalSearchParams.getFacetFields();
        List<String> esNameList = facetFieldList.stream().map(x -> x.getRetrievalName()).collect(Collectors.toList());
        String[] facetFieldArr = esNameList.toArray(new String[]{});
        LinkedHashMap<String, LinkedHashMap<String, Object>> facet = dynamicSearchService.facet(ClassesConstants.ELASTICSEARCH_INDEXES, completeQueryStr, facetQueryStr, facetFieldArr, retrievalSearchParams.getPageSizes());
        HashMap<String, Object> dictFacet = new HashMap<>();
        List<RetrievalFacetField> removeFacetFieldList = new ArrayList<>();
        List<SysDictType> dictTypeListByCache = dynamicCache.getDictTypeListByCache();
        for (RetrievalFacetField retrievalFacetField : facetFieldList) {
            String field = retrievalFacetField.getNameEn();
            LinkedHashMap<String, Object> fieldDataFacet = (LinkedHashMap<String, Object>) facet.get(field);
            if (fieldDataFacet.size() == 0) {
                // 分面字段下无数据的不现实。加入移除分面字段
                removeFacetFieldList.add(retrievalFacetField);
            } else {
                String dictId = retrievalFacetField.getDictId();
                if (StringUtils.isNotBlank(dictId) && !"0".equals(dictId) && !"null".equals(dictId)) {
                    SysDictType sysDictType = dictTypeListByCache.stream().filter(x -> dictId.equals(x.getDictId() + "")).findFirst().orElse(null);
                    if (sysDictType != null) {
                        List<SysDictData> dictDataList = sysDictType.getDictDataList();
                        List<String> removeKey = new ArrayList<>();
                        LinkedHashMap<String, Object> addMap = new LinkedHashMap<>();
                        for (String key : fieldDataFacet.keySet()) {
                            String dictLable = dictDataList.stream().filter(x -> key.equals(x.getDictValue())).map(x -> x.getDictLabel()).findFirst().orElse(key);
                            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(retrievalFacetField.getRetrievalName() + ".keyword", key + ".*");
                            Long aLong = dynamicSearchService.searchCount(ClassesConstants.ELASTICSEARCH_INDEXES, termQueryBuilder, null);
                            retrievalFacetField.setHaveChildren(aLong > 0);
                            addMap.put(dictLable, fieldDataFacet.get(key));
                            removeKey.add(key);
                            dictFacet.put(field + "." + dictLable, key);
                        }
                        for (String rkey : removeKey) {
                            fieldDataFacet.remove(rkey);
                        }
                        fieldDataFacet.putAll(addMap);
                    }
                }
            }
        }
        facetFieldList.removeAll(removeFacetFieldList);
        return R.success().data("facetFieldList", facetFieldList).data("facetResultMap", facet).data("dictFacetMap", dictFacet);
    }


    /**
     * 拼接完整查询语句
     * @param operator AND, OR, NOT, FILTER
     * @param queryBuilders
     * @return
     */
    private QueryBuilder getCompleteQueryStr(String operator, QueryBuilder... queryBuilders){
        BoolQueryBuilder completeQueryStr = QueryBuilders.boolQuery();
        for (QueryBuilder queryBuilder : queryBuilders) {
            if(queryBuilder != null){
                if(Objects.equals("NOT", operator)){
                    completeQueryStr.mustNot(queryBuilder);
                }else if(Objects.equals("OR", operator)){
                    completeQueryStr.should(queryBuilder);
                } if(Objects.equals("FILTER", operator)){
                    completeQueryStr.filter(QueryBuilders.boolQuery().must(queryBuilder));
                }else{
                    completeQueryStr.must(queryBuilder);
                }
            }
        }
        return completeQueryStr;
    }


    /**
     * 拼接资源库语句
     * @param retrievalSearchParams 资源库标识
     * @return
     */
    private QueryBuilder getDbQueryStr(RetrievalSearchParams retrievalSearchParams){
        String db = retrievalSearchParams.getDb();
        if(StringUtils.isNotBlank(db)){
            String dbEnForward = retrievalUtil.replaceRetrievalFieldForward("dbEn");
            QueryBuilder db_termQueryBuilder = QueryBuilders.termQuery(dbEnForward+".keyword", db);
            return db_termQueryBuilder;
        }
        return null;
    }

    /**
     * 拼接分面查询
     * @param retrievalSearchParams
     * @return
     */
    private QueryBuilder getFacetQueryStr(RetrievalSearchParams retrievalSearchParams){
        List<RetrievalFacetField> facetFields = retrievalSearchParams.getFacetFields();
        Map<String, List<String>> appointFacetFieldMap = retrievalSearchParams.getAppointFacetFieldMap();
        if(appointFacetFieldMap != null && appointFacetFieldMap.size() > 0){
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            BoolQueryBuilder fieldBoolQuery = null;
            for(String key: appointFacetFieldMap.keySet()){
                fieldBoolQuery = QueryBuilders.boolQuery();
                RetrievalFacetField retrievalFacetField = facetFields.stream().filter(x -> Objects.equals(x.getNameEn(), key)).findFirst().orElse(null);
                if(retrievalFacetField != null){
                    for (String v : appointFacetFieldMap.get(key)) {
                        fieldBoolQuery.must(QueryBuilders.termQuery(retrievalFacetField.getRetrievalName()+".keyword", v));
                        if("selectMultiple".equals(retrievalFacetField.getDataTypeName())){
                            fieldBoolQuery.should(QueryBuilders.wildcardQuery(retrievalFacetField.getRetrievalName()+".keyword", v+".*"));
                        }
                    }
                    boolQueryBuilder.must(fieldBoolQuery);
                }
            }
            return boolQueryBuilder;
        }
        return null;
    }




    /**
     * 说明：https://www.cnblogs.com/zxyza/p/9772009.html
     * 拼接检索词语句
     * @param retrievalSearchParams 查询实体
     * @return
     */
    private QueryBuilder getSearchWordQueryStr(RetrievalSearchParams retrievalSearchParams){
        String searchWord = retrievalSearchParams.getSearchWord();
        if(StringUtils.isNotBlank(searchWord) && !"null".equals(searchWord)){
            List<RetrievalSearchField> searchFields = retrievalSearchParams.getSearchFields();
            HashMap<String, String> weightRules = retrievalSearchParams.getWeightRules();
            try {
                if(searchFields != null && searchFields.size() > 0){
                    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                    Float boost = null;
                    for (RetrievalSearchField searchField : searchFields) {
                        String participle = searchField.getParticiple();
                        boost = Float.valueOf(1);
                        if(weightRules != null && weightRules.containsKey(searchField.getNameEn())){
                            boost = Float.parseFloat(weightRules.get(searchField.getNameEn()));
                        }
                        QueryBuilder fieldQueryBuilder = null;
                        if(ClassesConstants.IS_SEARCH_PARTICIPLE.equals(participle)){
                            boolQueryBuilder.should(QueryBuilders.matchQuery(searchField.getRetrievalName(), searchWord).operator(Operator.OR).boost(boost));
                        }else{
                            // 精准查询权重是分词查询的十倍
                            boolQueryBuilder.should(QueryBuilders.termQuery(searchField.getRetrievalName()+".keyword", searchWord).boost(boost * 10));
                        }

                    }
                    return boolQueryBuilder;
                }
            }catch (Exception e){
                LOGGER.error("拼接检索词语句出错!"+e.getMessage());
            }
        }
        return null;
    }

}
